package com.ninth_group.utils;

import com.ninth_group.function.TriFunction;
import com.ninth_group.po.CityInfo;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.util.List;
import java.util.Set;

@Component
public class QueryUtil {
    @Resource
    private HiveUtil hiveUtil;

    /**
     * 根据城市和省份名称获取城市信息
     * @param provinceName 省份名称
     * @param cityName 城市名称
     * @param getCityIdFunc 获取城市代码的函数
     * @return 城市基本信息
     */
    public <T> T getCityBaseInfo(String tableName,
                                 String provinceName,
                                 String cityName,
                                 Class<T> clazz,
                                 TriFunction<String, String, Class<T>, T> getCityIdFunc) {
        Set<CityInfo> cityDataIncludingProvince =
                CityInfoUtil.getCityDataIncludingProvince(hiveUtil);
        if (cityDataIncludingProvince.isEmpty()) return null;
        // 获取城市编码
        for (CityInfo cityInfo : cityDataIncludingProvince) {
            if (cityInfo.getProvince().equals(provinceName)
                    && cityInfo.getCity().equals(cityName)) {
                return getCityIdFunc.apply(cityInfo.getCityId(), tableName, clazz);
            }
        }
        return null;
    }

    public <T> T getCityExtraInfo(String tableName,
                                 String provinceName,
                                 String cityName,
                                 Class<T> clazz, // 获取城市代码的函数
                                 TriFunction<String, String, Class<T>, T> getCityIdFunc) {
        Set<CityInfo> cityDataIncludingProvince =
                CityInfoUtil.getCityDataIncludingProvince(hiveUtil);
        if (cityDataIncludingProvince.isEmpty()) return null;
        // 获取城市编码
        for (CityInfo cityInfo : cityDataIncludingProvince) {
            if (cityInfo.getProvince().equals(provinceName)
                    && cityInfo.getCity().equals(cityName)) {
                return getCityIdFunc.apply(cityInfo.getCityId(), tableName, clazz);
            }
        }
        return null;
    }

    public static <T> T getCityById(String cityId, String tableName, Class<T> clazz) {
        // 表是固定的, 只能在 city_base_info 中通过省份和城市名获取到对应的城市代码
        String sql = "SELECT * FROM " + tableName + " WHERE city_id = ?";
        try {
            Method mapRow = clazz.getMethod("mapRow", ResultSet.class);

            return HiveUtilHolder.getHiveUtil().queryForObject(sql, s -> {
                if (s == null) {
                    // 如果 ResultSet 为空，直接返回 null 或抛异常
                    return null;
                }

                try {
                    // 调用 mapRow 处理整个 ResultSet
                    return (T) mapRow.invoke(null, s);
                } catch (InvocationTargetException | IllegalAccessException  e) {
                    throw new RuntimeException(e);
                }
            }, cityId);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException(
                    "The class " + clazz.getName() +
                            " does not have a static method named 'mapRow' " +
                            "that takes a ResultSet as its only parameter.");
        }
    }

    public static <T> List<T> getCityByIdToList(String cid, String tableName, Class<T> clazz) {
        String sql = "SELECT * FROM " + tableName + " WHERE city_id = ?";
        try {
            Method mapRow = clazz.getMethod("mapRow", ResultSet.class);

            return HiveUtilHolder.getHiveUtil().queryForList(sql, s -> {
                if (s == null) {
                    return null;
                }
                try {
                    return (T) mapRow.invoke(null, s);
                } catch (Exception e) {
                    System.out.println("抛出异常");
                    throw new RuntimeException(e);
                }
            }, cid);

        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException(
                    "The class " + clazz.getName() +
                            " does not have a static method named 'mapRow' " +
                            "that takes a ResultSet as its only parameter.");
        }
    }

    private static final String CITY_BASE_INFO_TB = "city_base_info";
    private static final String FORECAST_7DAYS_TB = "forecast_7days";
    private static final String HOURLY_REALTIME_DATA_TB = "hourly_realtime_data";

    /**
     * 泛型主方法：根据 city_name + province_name 获取数据
     *
     * @param tableName        要查询的目标表名
     * @param cityIds          城市id列表, 如果只有一个id就传一个
     * @param clazz            返回对象类型
     * @param singleQueryFunc  单条查询函数（用于 city_base_info）
     * @param multiQueryFunc   多条查询函数（用于 forecast_7days / hourly_realtime_data）
     * @param <T>              返回泛型
     * @return                 单个结果或多个结果
     */
    public <T> Object getCityData(
            String tableName,
            List<String> cityIds,
            Class<T> clazz,
            TriFunction<String, String, Class<T>, T> singleQueryFunc,
            TriFunction<String, String, Class<T>, List<T>> multiQueryFunc) {


        // 判断是哪种表
        if (CITY_BASE_INFO_TB.equalsIgnoreCase(tableName)) {
            // 只取第一个
            String cityId = cityIds.getFirst();
            return singleQueryFunc.apply(cityId, tableName, clazz);
        } else if (FORECAST_7DAYS_TB.equalsIgnoreCase(tableName)
                || HOURLY_REALTIME_DATA_TB.equalsIgnoreCase(tableName)) {

            // 返回所有匹配的城市数据
            return cityIds.stream()
                    .map(f -> multiQueryFunc.apply(f, tableName, clazz))
                    .flatMap(List::stream)
                    .toList();
        } else {
            throw new IllegalArgumentException("不支持的表名: " + tableName);
        }
    }

}
